package own.application.system.shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;



public class MyRealm extends AuthorizingRealm {

	
	/*private ContextDao contextDao;
	
	public void setContextDao(ContextDao contextDao) {
		this.contextDao = contextDao;
	}*/

	/**
	 * 为当前登录的Subject授予角色和权限
	 * 
	 * @see 经测试:本例中该方法的调用时机为需授权资源被访问时
	 * @see 经测试:并且每次访问需授权资源时都会执行该方法中的逻辑,这表明本例中默认并未启用AuthorizationCache
	 * @see 个人感觉若使用了Spring3
	 *      .1开始提供的ConcurrentMapCache支持,则可灵活决定是否启用AuthorizationCache
	 * @see 比如说这里从数据库获取权限信息时,先去访问Spring3.1提供的缓存,而不使用Shior提供的AuthorizationCache
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		// 获取当前登录的用户名,等价于(String)principals.fromRealm(this.getName()).iterator().next()
		String currentUsername = (String) super
				.getAvailablePrincipal(principals);
		
		SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();
		// 实际中可能会像上面注释的那样从数据库取得
		if (null != currentUsername && "mike".equals(currentUsername)) {
			// 添加一个角色,不是配置意义上的添加,而是证明该用户拥有admin角色
			simpleAuthorInfo.addRole("admin");
			// 添加权限
			simpleAuthorInfo.addStringPermission("admin:manage");
			System.out.println("已为用户[mike]赋予了[admin]角色和[admin:manage]权限");
			return simpleAuthorInfo;
		}
		// 若该方法什么都不做直接返回null的话,就会导致任何用户访问/admin/listUser.jsp时都会自动跳转到unauthorizedUrl指定的地址
		// 详见applicationContext.xml中的<bean id="shiroFilter">的配置
		return null;
	}

	/**
	 * 验证当前登录的Subject
	 * 
	 * @see 经测试:本例中该方法的调用时机为LoginController.login()方法中执行Subject.login()时
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		
		/*if("3".equals(RedisUtil.redisTemplate.opsForValue().get(token.getUsername()))){
			throw new ExcessiveAttemptsException();
		}
		SysManagerEntity sm = contextDao.findSqlOneEntity(SysManagerEntity.class,
				"select * from sys_administrators where user_name = '"+token.getUsername()+"'");*/
		if (token.getUsername() == null) {
			throw new UnknownAccountException();
		}else if (token.getUsername() != null) {
			System.out.println(String.valueOf(token.getPassword()));
			if(!"123456".equals(String.valueOf(token.getPassword()))){
				Integer errorCount = 1;
				/*if(RedisUtil.redisTemplate.opsForValue().get(token.getUsername()) != null || "".equals(RedisUtil.redisTemplate.opsForValue().get(token.getUsername()))){
					errorCount = Integer.parseInt(RedisUtil.redisTemplate.opsForValue().get(token.getUsername()))+1;
				}*/
				//RedisUtil.redisTemplate.opsForValue().set(token.getUsername(), errorCount.toString(), 1, TimeUnit.DAYS);
				throw new IncorrectCredentialsException();
			}
		}
		//RedisUtil.redisTemplate.delete(sm.getUserName());
		//sm.setLastTime(new Date());
		//contextDao.update(sm);
		AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(
				token.getUsername(), token.getPassword(), this.getName());
		this.setSession(token.getUsername());
		return authcInfo;
	}

	/**
	 * 将一些数据放到ShiroSession中,以便于其它地方使用
	 * 
	 * @see 比如Controller,使用时直接用HttpSession.getAttribute(key)就可以取到
	 */
	private void setSession(Object value) {
		Subject currentUser = SecurityUtils.getSubject();
		if (null != currentUser) {
			Session session = currentUser.getSession();
			System.out
					.println("Session默认超时时间为[" + session.getTimeout() + "]毫秒");
			if (null != session) {
				System.out.println(session.getId());
				session.setAttribute(session.getId(), value);
			}
		}
	}
}
